# -*- coding:UTF-8 -*-
from bs4 import BeautifulSoup
import subprocess as sp
from lxml import etree
import requests
import random
import re


class AgentIp(object):
    def __init__(self, page, *args, **kwargs):
        self.page = page
        self.target_url = "http://www.xicidaili.com/nn/"
        self.target_headers = {'Upgrade-Insecure-Requests': '1',
                               'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/\
		58.0.3029.110 Safari/537.36',
                               'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                               'Referer': 'http://www.xicidaili.com/nn/',
                               'Accept-Encoding': 'gzip, deflate, sdch',
                               'Accept-Language': 'zh-CN,zh;q=0.8', }

    def get_proxys(self):
        """
        函数说明:获取IP代理
        Parameters:
            page - 高匿代理页数,默认获取第一页
        Returns:
            proxys_list - 代理列表
        """
        format_tuple = (self.target_url, self.page)
        target_url = '{}{}'.format(format_tuple[0], format_tuple[1])
        session = requests.Session()
        target_response = session.get(url=target_url, headers=self.target_headers)
        target_response.encoding = 'utf-8'
        # 获取网页信息
        target_html = target_response.text
        # 获取id为ip_list的table
        bf1_ip_list = BeautifulSoup(target_html, 'lxml')
        bf2_ip_list = BeautifulSoup(str(bf1_ip_list.find_all(id='ip_list')), 'lxml')
        ip_list_info = bf2_ip_list.table.contents
        # 存储代理的列表
        proxys_list = []
        # 爬取每个代理信息
        for index in range(len(ip_list_info)):
            if index % 2 == 1 and index != 1:
                dom = etree.HTML(str(ip_list_info[index]))
                ip = dom.xpath('//td[2]')
                port = dom.xpath('//td[3]')
                protocol = dom.xpath('//td[6]')
                proxys_list.append(protocol[0].text.lower() + ':' + ip[0].text + ':' + port[0].text)
        return proxys_list

    @staticmethod
    def check_ip(ip, lose_time, waste_time):
        """
        :param ip: 代理的ip地址
        :param lose_time: 匹配丢包数
        :param waste_time: 匹配平均时间
        :return: average_time - 代理ip平均耗时
        """
        # 命令 -n 要发送的回显请求数 -w 等待每次回复的超时时间(毫秒)
        cmd = "ping -n 3 -w 3 %s"
        # 执行命令
        p = sp.Popen(cmd % ip, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
        # 获得返回结果并解码
        out = p.stdout.read().decode("gbk")
        # 丢包数
        lose_time = lose_time.findall(out)
        # 当匹配到丢失包信息失败,默认为三次请求全部丢包,丢包数lose赋值为3
        if len(lose_time) == 0:
            lose = 3
        else:
            lose = int(lose_time[0])
        # 如果丢包数目大于2个,则认为连接超时,返回平均耗时1000ms
        if lose > 2:
            # 返回False
            return 1000
        # 如果丢包数目小于等于2个,获取平均耗时的时间
        else:
            # 平均时间
            average = waste_time.findall(out)
            # 当匹配耗时时间信息失败,默认三次请求严重超时,返回平均好使1000ms
            if len(average) == 0:
                return 1000
            else:
                average_time = int(average[0])
                # 返回平均耗时
                return average_time

    def initpattern(self):
        """
        函数说明:初始化正则表达式
        Parameters: 无
        Returns:
            lose_time - 匹配丢包数
            waste_time - 匹配平均时间
        Modify:
            2017-05-27
        """
        # 匹配丢包数
        lose_time = re.compile(u"丢失 = (\d+)", re.IGNORECASE)
        # 匹配平均时间
        waste_time = re.compile(u"平均 = (\d+)ms", re.IGNORECASE)
        return lose_time, waste_time


if __name__ == '__main__':
    ai = AgentIp(page=1)
    # 初始化正则表达式
    lose_time, waste_time = ai.initpattern()
    # 获取IP代理
    proxys_list = ai.get_proxys()
    print(proxys_list)

    # 如果平均时间超过200ms重新选取ip
    while True:
        # 从100个IP中随机选取一个IP作为代理进行访问
        proxy = random.choice(proxys_list)
        split_proxy = proxy.split(':')
        # 获取IP
        ip = split_proxy[1]
        # 检查ip
        average_time = ai.check_ip(ip, lose_time, waste_time)
        if average_time > 200:
            # 去掉不能使用的IP
            proxys_list.remove(proxy)
            print("ip 连接超时, 重新获取中!")
        if average_time < 200:
            break

    # 去掉已经使用的IP
    proxys_list.remove(proxy)
    proxy_dict = {split_proxy[0]: split_proxy[1] + ':' + split_proxy[2]}
    print("使用代理:{}".format(proxy_dict))
